#include <cstring>

#include "FileUtil.h"

namespace Logger
{
    FileUtil::FileUtil(const char *fileName)
        : fd_(::fopen(fileName, "ae")), buffer_(), writtenBytes_(0) // e：O_CLOEXEC，exec()时关闭
    {
        // setbuffer()文件缓冲区设置为本地缓冲区降低io次数提高性能，先内存缓冲后磁盘文件
        ::setbuffer(this->fd_, this->buffer_, sizeof(this->buffer_));
    }

    FileUtil::~FileUtil()
    {
        if (this->fd_)
        {
            ::fclose(this->fd_);
        }
    }

    void FileUtil::write(const char *data, size_t size)
    {
        size_t writen = 0;
        while (writen != size) // 未写完持续写
        {
            size_t remain = size - writen;
            size_t n = write1(data + writen, remain);
            if (n != remain)
            {
                int err = ::ferror(this->fd_);
                if (err)
                {
                    ::fprintf(stderr, "FileUtil::write() failed %s\n", ::strerror(err));
                    ::clearerr(this->fd_);
                    break;
                }
            }
            writen += n;
        }
        this->writtenBytes_ += writen;
    }

    void FileUtil::flush()
    {
        ::fflush(this->fd_);
    }

    size_t FileUtil::write1(const char *data, size_t size)
    {
        // 写入日志文件不太需要线程安全可以忍受部分乱序，考虑性能未使用线程安全fwrite()而是fwrite_unlocked()
        return ::fwrite_unlocked(data, 1, size, this->fd_); // 每个块大小1，块数量size，按1B逐个写入
    }
} // namespace Logger